/*
 * Copyright (c) 2009, Maxim Taran. All Rights Reserved.
 */

package max.utils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * User: MTaran
 * Date: 31.05.2007
 * Time: 18:05:26
 */

/**
 * В классе реализованы различные, часто используемые, методы для вывода различной информации в консоль и в виде строки.
 * @author Максим Таран
 */
public class Maxutils {
    static String dateformat = "yyyy.MM.dd HH:mm:ss.SSS";
    static SimpleDateFormat sdf = new SimpleDateFormat(dateformat);
    static String defaultmessage = " Max: ";

    /**
     * Конструктор с параметром определения формата времени, который будет использоваться для вывода в функциях {@link max.utils.Maxutils#timeMessage(String)}
     * и {@link max.utils.Maxutils#errorTimeMessage(String)}.
     * @param dateformat Строка в формате {@link java.text.SimpleDateFormat}.
     */
    public Maxutils(String dateformat) {
        Maxutils.dateformat = dateformat;
        init();
    }

    /**
     * В конструктор передаются параметры формата даты и сообщения по умолчанию.
     * @param dateformat Строка в формате {@link java.text.SimpleDateFormat}.
     * @param defaultmessage Идентификатор, который будет выводится после времени в сообщении.
     */
    public Maxutils(String dateformat, String defaultmessage) {
        Maxutils.dateformat = dateformat;
        Maxutils.defaultmessage = defaultmessage;
        init();
    }

    /**
     * Конструктор по-умолчанию.<p>
     * Чтобы установить в дальнейшем формат даты для вывода сообщений, необходимо использовать метод {@link max.utils.Maxutils#setDateFormat(String)}.<p>
     * Чтобы установить сообщение по умолчанию необходимо использовать метод {@link Maxutils#setDefaultMessage(String)}.
     */
    public Maxutils() {
        init();
    }

    /**
     * Метод используется для переинициализации формата даты и идентификатора.
     */
    protected static void init() {
        setDefaultMessage(defaultmessage);
        sdf = new SimpleDateFormat(dateformat);
    }

    /**
     * Метод, устанавливающий формат времени и даты при выводе сообщений методами {@link Maxutils#timeMessage(String)} и
     * {@link max.utils.Maxutils#errorTimeMessage(String)}.
     * @param dateformat Строка в формате {@link java.text.SimpleDateFormat}.
     */
    public static void setDateFormat(String dateformat) {
        Maxutils.dateformat = dateformat;
        init();
    }

    /**
     * Метод, устанавливающий текст по умолчанию, идущий после времени при вызове методов {@link max.utils.Maxutils#timeMessage(String)} и
     * {@link max.utils.Maxutils#errorTimeMessage(String)}. Если сообщение не нужно, то необходимо в качестве параметра передать пустую строку.
     * @param defaultmessage Идентификатор, который необходимо отображать после времени при выводе сообщения.
     */
    public static void setDefaultMessage(String defaultmessage) {
        if (defaultmessage.equals(""))
            Maxutils.defaultmessage = defaultmessage;
        else
            Maxutils.defaultmessage = " " + defaultmessage.trim() + ": ";
    }

    /**
     * Метод используется для формирования строки вывода для методов {@link max.utils.Maxutils#timeMessage(String)} и
     * {@link max.utils.Maxutils#errorTimeMessage(String)}.
     * @param s Сообщение, которое необходимо вывести.
     * @return Возвращает строку, сформатированную согласно настройкам класса.
     */
    protected static String outString(String s) {
        return sdf.format(new Date(System.currentTimeMillis())) + defaultmessage + s;
    }

    /**
     * Метод, выводящий сообщение вместе со временем. Сообщение выводится в стандартный поток вывода.
     * @param s Сообщение, которое необходимо вывести.
     */
    public static void timeMessage(String s) {
        System.out.println(outString(s));
    }

    /**
     * Метод, выводящий сообщение от ошибке вместе со временем. Сообщение выводится в поток ошибок.
     * @param s Сообщение, которое необходимо вывести
     */
    public static void errorTimeMessage(String s) {
        System.err.println(outString(s));
    }


    /**
     * Метод переделывает время в миллисекундах в строку формата: <i>количество_лет дней часов:минут:секунд.миллисекунд</i>.
     * @param mills Количество миллисекунд, которые надо перевести.
     * @return Возвращает строку формата: <i>y d hh:MM:ss.mmmm</i>
     */
    public static String getFormattedTime(long mills) {
        final long sec = 1000L; //количество миллисекунд в секунде
        final long min = sec * 60; //количество миллисекунд в минуте
        final long hour = min * 60; //количество миллисекунд в часе
        final long day = hour * 24; //количество миллисекунд в дне
        final long year = day * 365; //количество миллисекунд в году

        StringBuilder result = new StringBuilder();

        long var;
        if ((var = mills / year) > 0) { //вычисляем количество ролных лет
            result.append(String.valueOf(var)).append("y ");
            mills = mills - var * year;
        }
        if ((var = mills / day) > 0) { //вычисляем количество дней
            result.append(String.valueOf(var)).append("d ");
            mills = mills - var * day;
        }
        var = mills / hour;  //вычисляем количество часов
        result.append(leadZero((int) var, 2)).append(":");
        mills = mills - var * hour;

        var = mills / min; //вычисляем количество минут
        result.append(leadZero((int) var, 2)).append(":");
        mills = mills - var * min;

        var = mills / sec;//вычисляем количество секунд
        result.append(leadZero((int) var, 2)).append(".");
        mills = mills - var * sec;

        result.append(leadZero((int) mills, 3));

        return result.toString();
    }

    /**
     * Метод возвращает разницу между текущим временем и временем, переданным ему в качестве параметра.
     * Для перевода миллисепкунд в часы, минуты, секунда используется метод {@link max.utils.Maxutils#getFormattedTime(long)}.
     * @param mills Количество миллисекунд с начала эпохи, относительно которого необходимо найти разницу.
     * @return Возвращает разницу во времени относительно текущего времени
     */
    public static String diffTime(long mills) {
        return getFormattedTime(System.currentTimeMillis() - mills);
    }

    /**
     * Метод, преобразующий число в строку с необходимым количеством лидирующих нулей.
     * @param number Число, в начале которого необходимо добавить нули
     * @param numdigits Общее количество знаков, которое должно быть. Относительно этого параметра вычисляется количество лидирующих нулей
     * @return Возвращает строку вида 00012
     */
    public static String leadZero(int number, int numdigits) {
        String s = String.valueOf(number);
        int dif;
        if ((dif = numdigits - s.length()) > 0) {
            char[] ch = new char[dif];
            java.util.Arrays.fill(ch, '0');
            return new StringBuilder().append(ch).append(s).toString();
        } else
            return s;
    }

}
